use crate::token::{Token, TokenKind};

pub struct Lexer<'a> {
   chars: std::iter::Peekable<std::str::Chars<'a>>,
}

impl<'a> Lexer<'a> {
   pub fn new(input: &'a str) -> Self {
      Lexer {
         chars: input.chars().peekable(),
      }
   }

   pub fn next_token(&mut self) -> Token {
      self.skip_whitespace();

      match self.chars.next() {
         Some('+') => Token {
            kind: TokenKind::Plus,
         },
         Some('-') => Token {
            kind: TokenKind::Minus,
         },
         Some('*') => Token {
            kind: TokenKind::Asterisk,
         },
         Some('/') => Token {
            kind: TokenKind::Slash,
         },
         Some('^') => Token {
            kind: TokenKind::Caret,
         },
         Some('(') => Token {
            kind: TokenKind::LParen,
         },
         Some(')') => Token {
            kind: TokenKind::RParen,
         },
         Some(c) if c.is_ascii_digit() || c == '.' => {
            let mut num = String::new();
            num.push(c);
            while let Some(&next) = self.chars.peek() {
               if next.is_ascii_digit() || next == '.' {
                  num.push(self.chars.next().unwrap());
               } else {
                  break;
               }
            }
            Token {
               kind: TokenKind::Number(num.parse().unwrap()),
            }
         }
         None => Token {
            kind: TokenKind::Eof,
         },
         _ => panic!("Invalid character"),
      }
   }

   fn skip_whitespace(&mut self) {
      while let Some(&c) = self.chars.peek() {
         if c.is_whitespace() {
            self.chars.next();
         } else {
            break;
         }
      }
   }
}
